package cn.tramy.pinxian.common.util

import cn.tramy.pinxian.common.exception.BaseException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import reactor.core.publisher.Mono
import reactor.core.publisher.toMono
import java.util.*


fun runWithTry(block: () -> Unit): Result<Any> = ExecuteTool.executeWithTry { block() }

fun monoResult(block: () -> Unit): Mono<Result<Any>> = Mono.fromCallable { runWithTry(block) }

fun monoQueryResult(block: () -> Any?): Mono<Result<Any>> = ExecuteTool.executeQueryWithTry { block() }.toMono()
fun monoQueryPageResult(block: () -> List<Any>): Mono<Result<Any>> = ExecuteTool.executeQueryWithTry { ExecuteTool.queryPageData { block() } }.toMono()


fun ifTrue(condition: () -> Boolean, processor: () -> Unit) {
    if (condition()) processor()
}

fun logger(clazz: Class<*>): Logger = LoggerFactory.getLogger(clazz)


class Validator {

    val config: ValidationConfig = ValidationConfig()


    fun validate() {
        config.rules.forEach {
            //            ExecuteTool.conditionalException({ it.conditionSupplier() }, { it.exceptionSupplier() })

            if (it.conditionSupplier()) {
                it.executeFunc()
                it.exceptionSupplier?.let { throw it() }
            }

        }
    }

}

class ValidationConfig {

    val rules: MutableList<ValidationRule> = ArrayList()
    fun rule(block: ValidationRule.() -> Unit) {
        val validationRule = ValidationRule()
        validationRule.block()
        this.rules.add(validationRule)
    }
}


class ValidationRule {

    var conditionSupplier: () -> Boolean = { true }
        private set

    var exceptionSupplier: (() -> BaseException)? = { BaseException("Unknown", " Need to set validation exception") }
        private set

    var executeFunc: () -> Unit = {}

    fun ifTrue(block: () -> Boolean) {
        this.conditionSupplier = block
    }

    fun ifFalse(block: () -> Boolean) {
        ifTrue { !block() }
    }

    fun ifNull(block: () -> Any?) {
        this.conditionSupplier = { Objects.isNull(block()) }
    }

    fun ifNonNull(block: () -> Any?) {
        this.conditionSupplier = { Objects.nonNull(block()) }
    }

    fun exception(block: () -> BaseException) {
        this.exceptionSupplier = block
    }

    fun exec(block: () -> Unit) {
        this.executeFunc = block
    }
}


fun validationRules(block: ValidationConfig.() -> Unit): Validator {
    val validator = Validator()
    validator.config.block()
    return validator
}


fun main(args: Array<String>) {
    validationRules {
        rule {
            ifTrue { false }
            exception { BaseException("code", "test") }
        }
        rule {
            ifNull { null }
            exception { BaseException("code1", "NPE") }
        }
    }.validate()
}


